/*
** $Id: lstate.h $
** 全局状态
** See Copyright Notice in lua.h
*/

#ifndef lstate_h
#define lstate_h

#include "lua.h"


/* 这里包含的一些头文件需要这个定义 */
typedef struct CallInfo CallInfo;


#include "lobject.h"
#include "ltm.h"
#include "lzio.h"


/*
** 一些关于gc对象的说明：
** 所有Lua中的对象都必须保证在释放前可以以某种方式访问到，所以所有对象都属于下面这些列表中的一个(并且只有一个)，使用CommonHeader中的next字段作为连接
** 'allgc': 所有可收集对象
** 'finobj': 所有被标记为终结的对象(被终结器收集的对象)
** 'tobefnz': 所有准备终结的对象
** 'fixedgc': 所有不会被收集的对象(当前只有短字符串，比如保留字)
**
** 对于分代收集器， 其中一些列表具有代标记。每个标记指向该特定代的列表中的第一个元素;这一代一直延续到下一代。
**
** 'allgc' -> 'survival': 新对象;
** 'survival' -> 'old': 经过一次垃圾收集后仍然存活的对象
** 'old1' -> 'reallyold': 最后一次垃圾收集前就已经存在的老对象
** 'reallyold' -> NULL: 经过多次垃圾收集仍然存在的老对象
**
** 'finobj' -> 'finobjsur': 被标记为终结的新对象 new objects marked for finalization;
** 'finobjsur' -> 'finobjold1': survived   """";
** 'finobjold1' -> 'finobjrold': just old  """";
** 'finobjrold' -> NULL: really old       """".
**
** All lists can contain elements older than their main ages, due
** to 'luaC_checkfinalizer' and 'udata2finalize', which move
** objects between the normal lists and the "marked for finalization"
** lists. Moreover, barriers can age young objects in young lists as
** OLD0, which then become OLD1. However, a list never contains
** elements younger than their main ages.
**
** The generational collector also uses a pointer 'firstold1', which
** points to the first OLD1 object in the list. It is used to optimize
** 'markold'. (Potentially OLD1 objects can be anywhere between 'allgc'
** and 'reallyold', but often the list has no OLD1 objects or they are
** after 'old1'.) Note the difference between it and 'old1':
** 'firstold1': no OLD1 objects before this point; there can be all
**   ages after it.
** 'old1': no objects younger than OLD1 after this point.
*/

/*
** 此外，还有另一个控制灰色(gray)对象的列表集合这些列表链接字段'gclist'(所有可以变成gray的对象都有这样一个字段，这个字段在所有对象中都不相同，但是他总是具有这个名称)
** 所有的gray对象必须属于下面这些列表中的一个，并且这些列表中的所有对象都必须是灰色的(下面有两个例外)
** 'gray': 普通的灰色对象，仍然等待被访问
** 'grayagain': 必须在原子(atomic)阶段被再次访问的对象
**   他包含
**   - 通过写入屏障的黑色对象
**   - 传播(propagate)阶段所有类型的弱表
**   - 所有线程
** 'weak': 具有将被清除的弱值表
** 'ephemeron': 带有 white->white 条目的蜉蝣表;
** 'allweak': 拥有将被清除的弱值/弱key的表
**
** "灰色规则"的例外：
** - 分代模式中的TOUCHED2对象报错在gray列表中(因为他们必须在周期结束时再次被访问), 
** but they are marked black because assignments to them must activate barriers (to move them back to TOUCHED1).
** - 打开的upvalue保持灰色以避免屏障，但是他们不会再gray列表中(他们甚至没有’gclist'字段)
*/



/*
** 'nCcalls':  这个次数包含两部分：低16位统计C栈中的递归调用次数，高16位统计栈中non-yieldable的调用次数
*/


/* 如果这个线程的栈上没有任何的non-yieldable调用返回true */
#define yieldable(L)		(((L)->nCcalls & 0xffff0000) == 0)

/* C调用的真实数量 */
#define getCcalls(L)	((L)->nCcalls & 0xffff)


/* 增加non-yieldable调用数量 */
#define incnny(L)	((L)->nCcalls += 0x10000)

/* 减少non-yieldable调用的数量 */
#define decnny(L)	((L)->nCcalls -= 0x10000)

/* Non-yieldable调用增加 */
#define nyci	(0x10000 | 1)




struct lua_longjmp;  /* defined in ldo.c */


/*
** 相对于信号的原子类型，用以更好的确保 'lua_sethook' 是线程安全的
*/
#if !defined(l_signalT)
#include <signal.h>
#define l_signalT	sig_atomic_t
#endif


/*
** 额外空间用来处理元方法调用和一些其他额外操作，这些空间不包括在'stack_last'中，他只用于避免栈检测，
** 包括这个元素不将被迅速弹出和他将在压入后不被栈进行栈检测
** 函数对象永远不会使用这个额外空间，所以他不需要保持干净
*/
#define EXTRA_STACK   5


#define BASIC_STACK_SIZE        (2*LUA_MINSTACK)

#define stacksize(th)	cast_int((th)->stack_last.p - (th)->stack.p)


/* gc类型 */
#define KGC_INC		0	/* 增量gc */
#define KGC_GEN		1	/* 分代gc */

// 处理短字符串的字符串表
typedef struct stringtable {
  TString **hash; /* TString的hash链表 */
  int nuse;  /* 使用中的元素个数 */
  int size; /* stringtable大小(容量) */
} stringtable;


/*
** 调用信息
** 'u':
**  'l'字段只用于Lua函数
**  'c'字段只用于C函数
** 'u2':
**  'funcidx'字段只用于在保护调用下的C函数
**  'nyield'字段只在 当一个函数做挂起(yield)时使用(从挂起到下一次延续);
**  'nres'只在从一个函数返回时关闭待关闭变量时使用
**  字段 'transferinfo' 只在 call/return 钩子期间, 函数开始之前或结束之后使用
*/
struct CallInfo {
  StkIdRel func;  /* 方法在栈中的索引 */
  StkIdRel top;  /* 方法的栈顶 */
  struct CallInfo *previous, *next;  /* 动态的调用链接 */
  union {
    struct {  /* Lua方法 */
      const Instruction *savedpc; /* 当前执行到的指令 */
      volatile l_signalT trap;  /* 是否需要被捕捉(hook是否开启) */
      int nextraargs;  /* 可变参数函数的额外参数数量 */
    } l;
    struct {  /* C方法 */
      lua_KFunction k;  /* yields状态下的延续函数 */
      ptrdiff_t old_errfunc;
      lua_KContext ctx;  /* yields状态下的延续上下文信息 */
    } c;
  } u;
  union {
    int funcidx;  /* 被调用方法索引 */
    int nyield;  /* 让出值的数量 */
    int nres;  /* 返回值数量 */
    struct {  /* 被转移值的信息 (for call/return hooks) */
      unsigned short ftransfer;  /* 第一个被转移值的偏移 */
      unsigned short ntransfer;  /* 被转移值数量 */
    } transferinfo;
  } u2;
  short nresults;  /* 这个方法预期返回值个数  */
  unsigned short callstatus;  /* 调用状态 */
};


/*
** CallInfo状态的位
*/
#define CIST_OAH	(1<<0)	/* ’allowhook'的原始值 */
#define CIST_C		(1<<1)	/* 正在运行一个C函数 */
#define CIST_FRESH	(1<<2)	/* 正在一个新的“luaV_execute”帧 */
#define CIST_HOOKED	(1<<3)	/* 正在运行一个debug钩子 */
#define CIST_YPCALL	(1<<4)	/* 正在做一次可让出的受保护调用 */
#define CIST_TAIL	(1<<5)	/* 尾调用 */
#define CIST_HOOKYIELD	(1<<6)	/* 上一次钩子调用让出 */
#define CIST_FIN	(1<<7)	/* 正在调用一个终结器 */
#define CIST_TRAN	(1<<8)	/* 'ci' 有转移信息 */
#define CIST_CLSRET	(1<<9)  /* 函数正在关闭待关闭变量 */
/* 10-12位用于 CIST_RECST (见下文) */
#define CIST_RECST	10
#if defined(LUA_COMPAT_LT_LE)
#define CIST_LEQ	(1<<13)  /* using __lt for __le */
#endif


/*
** CIST_RECST 保存 "recover status(恢复状态)", 用于在协程中关闭待关闭变量是保留错误状态,因此 Lua可以在因错误而调用__close方法让出之后正确地恢复。
*/
#define getcistrecst(ci)     (((ci)->callstatus >> CIST_RECST) & 7)
#define setcistrecst(ci,st)  \
  check_exp(((st) & 7) == (st), \
            ((ci)->callstatus = ((ci)->callstatus & ~(7 << CIST_RECST))  \
                                                  | ((st) << CIST_RECST)))


/* 方法是一个Lua函数 */
#define isLua(ci)	(!((ci)->callstatus & CIST_C))

/* 运行的Lua代码(不是一个hook) */
#define isLuacode(ci)	(!((ci)->callstatus & (CIST_C | CIST_HOOKED)))

/* assume that CIST_OAH has offset 0 and that 'v' is strictly 0/1 */
#define setoah(st,v)	((st) = ((st) & ~CIST_OAH) | (v))
#define getoah(st)	((st) & CIST_OAH)


/*
** 'global state', 所有的线程共享这个state
*/
typedef struct global_State {
  lua_Alloc frealloc;  /* 分配内存的方法 */
  void *ud;         /* 分配内存的用户数据(用以调用分配内存时传入) */
  l_mem totalbytes;  /* 当前已经分配内存的总字节数 - GCdebt */
  l_mem GCdebt;  /* 尚未由收集器补偿的已分配字节(GC的债务(负数)，当债务 > 0 时，触发GC) */
  lu_mem GCestimate;  /* 正在使用的非垃圾内存预估 */
  lu_mem lastatomic;  /* 参见文件 'lgc.c' 的 'genstep' */
  stringtable strt;  /* 字符串的hash表 */
  TValue l_registry;  /* 注册表 */
  TValue nilvalue;  /* 全局的nil值 */
  unsigned int seed;  /* hash的随机数种 */
  lu_byte currentwhite; /* 当前白 */
  lu_byte gcstate;  /* gc的状态 */
  lu_byte gckind;  /* 当前运行的gc类型 */
  lu_byte gcstopem;  /* 停止紧急收集 */
  lu_byte genminormul;  /* 次级分代回收倍率 */
  lu_byte genmajormul;  /* 主要分代回收倍率 */
  lu_byte gcstp;  /* GC是否正在运行 */
  lu_byte gcemergency;  /* 紧急回收时为true */
  lu_byte gcpause;  /* 连续GC之间的间隔大小 */
  lu_byte gcstepmul;  /* GC "speed" */
  lu_byte gcstepsize;  /* (log2 of) GC 粒度 */
  GCObject *allgc;  /* 所有可收集对象 */
  GCObject **sweepgc;  /* 列表中清扫的当前位置 */
  GCObject *finobj;  /* 所有带有终结器的可收集对象 */
  GCObject *gray;  /* 灰色对象列表 */
  GCObject *grayagain;  /* 在原子阶段被遍历的对象列表 */
  GCObject *weak;  /* 弱值表(弱values)列表 */
  GCObject *ephemeron;  /* 弱键(弱keys)列表 */
  GCObject *allweak;  /* 弱键值(弱kv)列表 */
  GCObject *tobefnz;  /* 要GC的Userdata数据 */
  GCObject *fixedgc;  /* 不被收集的对象列表(可收集但不收集的，如关键字字符串) */
  /* 分代GC字段 */
  GCObject *survival;  /* start of objects that survived one GC cycle */
  GCObject *old1;  /* start of old1 objects */
  GCObject *reallyold;  /* objects more than one cycle old ("really old") */
  GCObject *firstold1;  /* first OLD1 object in the list (if any) */
  GCObject *finobjsur;  /* list of survival objects with finalizers */
  GCObject *finobjold1;  /* list of old1 objects with finalizers */
  GCObject *finobjrold;  /* list of really old objects with finalizers */
  struct lua_State *twups;  /* 打开upvalue的线程列表 */
  lua_CFunction panic;  /* 紧急函数(在unprotected的函数调用中出错时调用) */
  struct lua_State *mainthread; // 主线程
  TString *memerrmsg;  /* 内存分配错误信息 */
  TString *tmname[TM_N];  /* 元方法名称数组 */
  struct Table *mt[LUA_NUMTYPES];  /* 基础类型的元表 */
  TString *strcache[STRCACHE_N][STRCACHE_M];  /* API的字符串缓存 */
  lua_WarnFunction warnf;  /* 警告方法 */
  void *ud_warn;         /* 'warnf'的辅助数据 */
} global_State;


/*
** 每个线程的状态
** 一个不透明的结构， 它指向一条线程并间接（通过该线程）引用了整个 Lua 解释器的状态。
** Lua 库是完全可重入的： 它没有任何全局变量。 状态机所有的信息都可以通过这个结构访问到。
*/
struct lua_State {
  CommonHeader;
  lu_byte status; /* 当前线程状态 */
  lu_byte allowhook;  /* hook(钩子)开关 */
  unsigned short nci;  /* 'ci'调用的层数 */
  StkIdRel top;  /* 栈顶位置，栈的第一个空闲节点 */
  global_State *l_G;
  CallInfo *ci;  /* 当前方法的调用信息 */
  StkIdRel stack_last;  /* 栈尾部(最后一个元素+1) */
  StkIdRel stack;  /* 栈底 */
  UpVal *openupval;  /* 上值列表 */
  StkIdRel tbclist;  /* 待关闭变量列表(函数运行完成后准备关闭的函数) */
  GCObject *gclist;
  struct lua_State *twups;  /* 打开upvalue的线程列表 */
  struct lua_longjmp *errorJmp;  /* 当前的错误恢复点 */
  CallInfo base_ci;  /* 第一层调用信息 (C calling Lua) */
  volatile lua_Hook hook; /* hook函数 */
  ptrdiff_t errfunc;  /* 当前错误处理函数 (栈索引) */
  l_uint32 nCcalls;  /* 这个次数包含两部分：低16位统计C栈中的嵌套调用次数，高16位统计栈中non-yieldable的调用次数 */
  int oldpc;  /* pc(program count, 程序计数器，当前正在执行的命令的位置)，oldpc: 上一条pc */
  int basehookcount;
  int hookcount;
  volatile l_signalT hookmask;
};


#define G(L)	(L->l_G)

/*
** 'g->nilvalue'变成一个nil值表示状态已经构建完毕
*/
#define completestate(g)	ttisnil(&g->nilvalue)


/*
** 可收集对象的Union (只是为了转换)
** ISO C99, 6.5.2.3 p.5:
** “如果一个联合包含几个共享公共初始序列的结构[…]]并且联合对象包含这些结构之一，则允许在任何可见的联合完整类型声明的地方检查它们的公共初始部分。“
** GCUnion中所有的结构都是以CommonHeader开始，所以可以将GCUnion指针视为一个可以指向任何类型GCObject的指针
*/
union GCUnion {
  GCObject gc;  /* common header */
  struct TString ts;
  struct Udata u;
  union Closure cl;
  struct Table h;
  struct Proto p;
  struct lua_State th;  /* thread */
  struct UpVal upv;
};


/*
** ISO C99, 6.7.2.1 p.14:
** 一个指向union对象的指针，经过适当转换，指针指向他的成员，反之亦然
*/
#define cast_u(o)	cast(union GCUnion *, (o))

/* 转换所有的GCObject为指定的值 */
#define gco2ts(o)  \
	check_exp(novariant((o)->tt) == LUA_TSTRING, &((cast_u(o))->ts))
#define gco2u(o)  check_exp((o)->tt == LUA_VUSERDATA, &((cast_u(o))->u))
#define gco2lcl(o)  check_exp((o)->tt == LUA_VLCL, &((cast_u(o))->cl.l))
#define gco2ccl(o)  check_exp((o)->tt == LUA_VCCL, &((cast_u(o))->cl.c))
#define gco2cl(o)  \
	check_exp(novariant((o)->tt) == LUA_TFUNCTION, &((cast_u(o))->cl))
#define gco2t(o)  check_exp((o)->tt == LUA_VTABLE, &((cast_u(o))->h))
#define gco2p(o)  check_exp((o)->tt == LUA_VPROTO, &((cast_u(o))->p))
#define gco2th(o)  check_exp((o)->tt == LUA_VTHREAD, &((cast_u(o))->th))
#define gco2upv(o)	check_exp((o)->tt == LUA_VUPVAL, &((cast_u(o))->upv))


/*
** 将Lua对象转换成GCObject(访问’tt'尝试确保v是一个Lua对象)
*/
#define obj2gco(v)	check_exp((v)->tt >= LUA_TSTRING, &(cast_u(v)->gc))


/* 总使用内存的精确字节数 */
#define gettotalbytes(g)	cast(lu_mem, (g)->totalbytes + (g)->GCdebt)

LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);
LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
LUAI_FUNC void luaE_freeCI (lua_State *L);
LUAI_FUNC void luaE_shrinkCI (lua_State *L);
LUAI_FUNC void luaE_checkcstack (lua_State *L);
LUAI_FUNC void luaE_incCstack (lua_State *L);
LUAI_FUNC void luaE_warning (lua_State *L, const char *msg, int tocont);
LUAI_FUNC void luaE_warnerror (lua_State *L, const char *where);
LUAI_FUNC int luaE_resetthread (lua_State *L, int status);


#endif

